package domain;

import java.util.ArrayList;
import java.util.List;
import java.util.Observable;

public class Library extends Observable {
    private static Library instance;

    public static Library getInstance() {
        if (instance == null)
            instance = new Library();
        return instance;
    }

    private List<Copy> copies;
    private List<Customer> customers;
    private List<Loan> loans;
    private List<Book> books;

    private Library() {
        copies = new ArrayList<Copy>();
        customers = new ArrayList<Customer>();
        loans = new ArrayList<Loan>();
        books = new ArrayList<Book>();
    }

    public Loan createAndAddLoan(Customer customer, Copy copy) {
        if (!isCopyLent(copy)) {
            Loan l = new Loan(customer, copy);
            loans.add(l);
            copy.addLoan(l);
            doNotify();
            return l;
        } else {
            return null;
        }
    }

    public boolean removeBook(Book book) {
        boolean deleted = books.remove(book);
        doNotify();
        return deleted;
    }

    public Customer createAndAddCustomer(String name, String surname) {
        Customer c = new Customer(name, surname);
        customers.add(c);
        doNotify();
        return c;
    }

    public Book createAndAddBook(String name) {
        Book b = new Book(name);
        books.add(b);
        java.util.Collections.sort(books);
        doNotify();
        return b;
    }

    public Copy createAndAddCopy(Book title) {
        Copy c = new Copy(title);
        copies.add(c);
        doNotify();
        title.doNotify();
        return c;
    }

    public void removeCopy(Copy copy) {
        copies.remove(copy);
        copy.getTitle().doNotify();
        doNotify();
    }

    public void returnLoan(Loan loan) {
        loan.returnCopy();
        doNotify();
    }

    public Book findByBookTitle(String title) {
        for (Book b : books) {
            if (b.getName().equals(title)) {
                return b;
            }
        }
        return null;
    }

    public boolean isCopyLent(Copy copy) {
        for (Loan l : loans) {
            if (l.getCopy().equals(copy) && l.isLent()) {
                return true;
            }
        }
        return false;
    }

    public List<Copy> getCopiesOfBook(Book book) {
        List<Copy> res = new ArrayList<Copy>();
        for (Copy c : copies) {
            if (c.getTitle().equals(book)) {
                res.add(c);
            }
        }

        return res;
    }

    public List<Loan> getLentCopiesOfBook(Book book) {
        List<Loan> lentCopies = new ArrayList<Loan>();
        for (Loan l : loans) {
            if (l.getCopy().getTitle().equals(book) && l.isLent()) {
                lentCopies.add(l);
            }
        }
        return lentCopies;
    }

    public List<Loan> getCustomerLoans(Customer customer) {
        List<Loan> lentCopies = new ArrayList<Loan>();
        for (Loan l : loans) {
            if (l.getCustomer().equals(customer)) {
                lentCopies.add(l);
            }
        }
        return lentCopies;
    }

    public List<Loan> getCustomerOpenLoans(Customer customer) {
        List<Loan> lentCopies = new ArrayList<Loan>();
        for (Loan l : loans) {
            if (l.isLent() && l.getCustomer().equals(customer)) {
                lentCopies.add(l);
            }
        }
        return lentCopies;
    }

    public List<Loan> getCustomerOverdueLoans(Customer customer) {
        List<Loan> lentCopies = new ArrayList<Loan>();
        for (Loan l : loans) {
            if (l.isOverdue() && l.getCustomer().equals(customer)) {
                lentCopies.add(l);
            }
        }
        return lentCopies;
    }

    public List<Loan> getOverdueLoans() {
        List<Loan> overdueLoans = new ArrayList<Loan>();
        for (Loan l : getLoans()) {
            if (l.isOverdue())
                overdueLoans.add(l);
        }
        return overdueLoans;
    }

    public List<Copy> getAvailableCopies() {
        return getCopies(false);
    }

    public List<Copy> getLentOutBooks() {
        return getCopies(true);
    }

    private List<Copy> getCopies(boolean isLent) {
        List<Copy> retCopies = new ArrayList<Copy>();
        for (Copy c : copies) {
            if (isLent == isCopyLent(c)) {
                retCopies.add(c);
            }
        }
        return retCopies;
    }

    public List<Copy> getCopies() {
        return copies;
    }

    public List<Loan> getLoans() {
        return loans;
    }

    public List<Loan> getOpenLoans() {
        List<Loan> openLoans = new ArrayList<Loan>();
        for (Loan loan : loans) {
            if (loan.isLent()) {
                openLoans.add(loan);
            }
        }
        return openLoans;
    }

    public List<Book> getBooks() {
        java.util.Collections.sort(books);
        return books;
    }

    public List<Customer> getCustomers() {
        return customers;
    }

    void doNotify() {
        setChanged();
        notifyObservers();
    }

    @Override
    public int hashCode() {
        return System.identityHashCode(this);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        return false;
    }

}
